#include <stdio.h>
#include <allegro.h>
#include <time.h>
#include <ctype.h>
#include "vida.h"

#define WIDTH 600
#define HEIGHT 600

#define W_PADRAO 20
#define H_PADRAO 20

#define COR_VIDA makecol(0, 255, 0)
#define COR_SELECT makecol(255, 255, 255)
#define COR_STR makecol(255, 255, 0)

BITMAP *buffer;
tabuleiro t;

/* largurao do bloco de vida */
int tamx;
/* altura do bloco de vida */
int tamy;

/* controla pause do programa */
bool pausesim;

char last_space;

void inicializa()
{
   /* INICIO DA INICIALIZACAO DO ALLEGRO */

   allegro_init();
   set_config_file("jogo.cfg");
   install_timer();
   install_keyboard();
   install_mouse();
   set_color_depth(32); 
   if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, WIDTH, HEIGHT, 0, 0))
   {
        printf("Video Error: %s", allegro_error);
        exit(1);
   }
   buffer = create_bitmap(WIDTH, HEIGHT);



   /* FIM DA INICIALIZACAO DO ALLEGRO */

   tamx = WIDTH / t->coluna;
   tamy = HEIGHT / t->linha;

   pausesim = true;
}

/* imprime ajuda na saida padrao e termina execucao */
void imprime_ajuda()
{
   printf("Uso:\n"
          "     -l [int]         -- define largura\n"
          "     -a [int]         -- define altura\n"
          "     -i [int_x:int_y] -- insere vida na posicao x:y\n"
          "     -r [int]         -- gera mapa aleatorio com densidade informada\n"
          "Nao utilize -l ou -a apos inserir vida\n"
          "Vida em posicoes invalidas nao sao inseridas nem alertadas\n"
          "Comando durante exeucao:\n"
          "ESPACO - pausa/despausa simulacao\n"
          "BOTAO ESQUERDO MOUSE - adiciona vida na posicao do mouse\n"
          "BOTAO DIREITO MOUSE - retira vida na posicao do mouse\n\n");       
   exit(0);
}

/* pega inteiro passado como argumento para o programa */
int pega_int_param(char* str)
{
   int i = 0;
   while(str[i])
      if (!isdigit(str[i++]))
      {
         str[i-1] = '\0';
         break;
      }

   return atoi(str);
}

/* cria tabuleiro baseado na entrada dos argumentos */
tabuleiro pega_entrada(int argc, char** argv)
{
   tabuleiro t;
   int altura, largura, i, vidax, viday, n_rnd;
   bool alocada;
   altura  = H_PADRAO;
   largura = W_PADRAO;
   alocada = false;

   /* sem parametros */
   if (argc > 1)
   {
      for(i=1; i<argc; i++)
      {
         if (argv[i][0] != '-' || argv[i][1] == 'h')
         {            
            imprime_ajuda();
         }

         /* suportamos apenas argumentos de 1 caractere */
         switch((int)argv[i][1])
         {
            case 'l':
               if (i+1 < argc && (largura=pega_int_param(argv[++i]))==0)
                  largura=W_PADRAO;
               break;

            case 'a':
               if (i+1 < argc && (altura=pega_int_param(argv[++i]))==0)
                  altura=H_PADRAO;
               break;

            case 'i':
               if (!alocada)
               {
                  t = (tabuleiro)malloc(sizeof(struct tabuleiro));
                  cria_matriz(t, altura, largura);
                  alocada = true;
               }
               if (i+1 < argc)
               {
                  vidax = pega_int_param(argv[++i]);
                  viday = pega_int_param(&argv[i][strlen(argv[i])+1]);
                  insere_vida(t, vidax, viday);
               }
               break;

            case 'r':
               if (!alocada)
               {
                  t = (tabuleiro)malloc(sizeof(struct tabuleiro));
                  cria_matriz(t, altura, largura);
                  alocada = true;
               }
               if (i+1 < argc)
                  n_rnd = pega_int_param(argv[++i]);
               else
               {
                  fprintf(stderr, "AVISO: -r pede argumento inteiro, definindo 0\n");
                  n_rnd = 0;
               }

               gera_rnd(t, n_rnd);
               break;

         }
      }
   }

   if (!alocada)
   {
      t = (tabuleiro)malloc(sizeof(struct tabuleiro));
      cria_matriz(t, altura, largura);
      alocada = true;
   }

   if (altura * largura > HEIGHT * WIDTH)
      fprintf(stderr, "AVISO: Tamanho do mapa implica em tamanho de celula menor que 1 pixel!\n");

   return t;
}

/* desenha um bloco de vertice x, y, na tela */
void desenha_bloco(int x, int y, int cor)
{
   rectfill(buffer, x, y, x+tamx, y+tamy, cor);
}

/* tranforma coordenadas do tabuleiro para coordenadas da tela */
void tabuleiro_tela(int posx, int posy, int *telax, int *telay)
{
   *telax = posx * tamx;
   *telay = posy * tamy;
}

/* converte posicao da tela para posicao do tabuleiro */
void tela_tabuleiro(int telax, int telay, int* posx, int* posy)
{
   *posx = telax / tamx;
   *posy = telay / tamy;
}

/* dado uma posicao da tela, devolve o vertice superior esquerdo do bloco */
void pega_bloco(int posx, int posy, int* blocox, int* blocoy)
{
   *blocox = (posx / tamx) * tamx;
   *blocoy = (posy / tamy) * tamy;
}

/* analisa o que eh feito pelo mouse */
void mouse_input()
{
   int x, y, tabx, taby;

   if (mouse_needs_poll())
      poll_mouse();

   pega_bloco(mouse_x, mouse_y, &x, &y);
   desenha_bloco(x, y, COR_SELECT);

   /* se o mouse for clicado, adicione vida */
   if (mouse_b & 1)
   {
      tela_tabuleiro(mouse_x, mouse_y, &x, &y);
      insere_vida(t, x, y);
   }

   /* se o segundo botao do  mouse for clicado, retire vida */
   if (mouse_b & 2)
   {
      tela_tabuleiro(mouse_x, mouse_y, &x, &y);
      retira_vida(t, x, y);
   }

}

void teclado_input()
{
   if (key[KEY_SPACE] && !last_space)
      pausesim = !pausesim;

   last_space = key[KEY_SPACE];
}

int atualiza()
{  
   int i, x, y;
   
   teclado_input();

   for(i=0; i < t->coluna*t->linha; i++)
   {
      if (t->atual[i] == vivo)
      {
         tabuleiro_abs(t, i, &x, &y);
         tabuleiro_tela(x, y, &x, &y);       
         desenha_bloco(x, y, COR_VIDA);
      }
   }

   if (pausesim)
   {
      mouse_input();
      return 0;
   }

   // aqui vem a chamada para a funcao que gerencia as threads

   memcpy(t->anterior, t->atual, t->coluna*t->linha);
   /* //DESCOMENTE ESTA PARTE PARA O JOGO FUNICONAR SEM THREAD =)
   parametros parametro;
   parametro.t = t;
   parametro.pos_inicial = 0;
   parametro.num_blocos = t->coluna*t->linha;
   
   atualiza_tabuleiro(&parametro);*/
   calcula_proximo(t);
   return 0;
}

void desenha()
{
   if (pausesim)
   {
      textout_ex(buffer, font, "Simulacao pausada", WIDTH/2 - 100, 20, COR_STR, -1);
   }

   blit(buffer, screen, 0, 0, 0, 0, buffer->w, buffer->h);
   clear_bitmap(buffer);
}

/* escreve script com dados do ultimo momento de execucao */
void escreve_script()
{
   int i, tam, x, y;
   FILE* file = fopen("vidascript", "w");

   fprintf(file, "./jogovida -a %d -l %d ", t->linha, t->coluna);

   tam = t->linha*t->coluna;
   for(i=0; i<tam; i++)
      if (t->atual[i] == vivo)
      {
         tabuleiro_abs(t, i, &x, &y);
         fprintf(file, "-i %d:%d ", x, y);
      }

   fclose(file);
}

int main(int argn, char** argv)
{
   t = pega_entrada(argn, argv);

   inicializa();

   while (!key[KEY_ESC])
   {
      atualiza();
      vsync();
      desenha();
   }      

   escreve_script();
   
   destroy_bitmap(buffer);
   libera_tabuleiro(t);
   allegro_exit();
   return 0;
}
END_OF_MAIN();
